#include <sys/stat.h>
#include <unistd.h>
#include <System.h>
#include <createFileOnDisk.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <fstream>
#include <SuperBlock.h>
#include <GroupDesription.h>
#include <BlockBitmap.h>
#include <FCB.h>
#include <DateTime.h>
#include <AddrLinkedList.h>
#include <Block.h>
#include <DirItem.h>
#include <exception>
//私有函数申明
int __getGroupId(int addr);                            //得到某个地址所属的组号
int __getActualAddr(fstream& fs, FCB fcb, int vir);    //得到文件内容虚拟块号的实际地址
int __getAddrStart(fstream& fs, FCB fcb);              //得到inode第一个直接块引用位置
int __comfirmABlock(fstream& fs, int addr);            //确认一个块的使用
int __releaseABlock(fstream& fs, int addr);            //释放一个块的使用
int __getABlock(fstream& fs);                          //得一个空的块
int __bindABlock(fstream& fs, int to);                 //为某个位置绑定一个空白块（包括__comfirmABlock）
FCB __getEmptyFCB(int, int);                           //得到一个空的FCB结构体
FCB __reloadFCB(fstream& fs, FCB origin);              //重新加载FCB
bool __updateFCB(fstream& fs, FCB origin);             //更新FCB
FCB* __loadFCB(fstream& fs, int addr);                 //加载FCB，加载失败返回0
void __setZero(fstream& fs, int addr);                 //把某个位置置0


//判断一个文件是否是合格的虚拟磁盘文件
bool isADisk(string filename)
{
    //文件名长度是否合适
    if(filename.size() < 5)  return false;
    	
    //文件格式是否正确
    const char* fName = filename.c_str();
    char format[6];
    strncpy(format, fName + filename.size() - 5, 5);
    format[5] = 0;
    if(strcmp(format, ".disk") != 0) return false;
    	
    //文件是否存在
    ifstream file;
    file.open(filename, ios::binary | ios::in | ios::ate);
    if(file.fail())
    {
        cout << "file open failed" << endl;
        file.close();
        return false;
    }
    
    //文件大小是否合适
    int blockGroupAccount = 0;
    struct stat statbuf;  
    stat(filename.c_str(), &statbuf);  
    int size=statbuf.st_size; 
    if(size % M != 0)    //大小需要满足M的整数倍
    {
        return false;
    }else
    {
        blockGroupAccount = size / M;
    }
    
    //是否有文件系统标识符
    int maxSize = blockGroupAccount * M;
    int flag = false;
    for(int i = 0; i < blockGroupAccount; i++)
    {
        int superBlockPostion = i * M + groupOffset;
        GroupDescription group;
        file.seekg(superBlockPostion);
        file.read((char*)&group, sizeof(group));
        if(group.super_block != 0 && group.super_block < maxSize - sizeof(SuperBlock))
        {
            file.seekg(group.super_block);
            SuperBlock superBlock;
            file.read((char*)&superBlock, sizeof(superBlock));
            if(superBlock.mask == mask)
            {
                flag = true;
                break;
            }
        }
    }
    
    file.close();
    return flag;
}

//创建一个指定大小的虚拟磁盘文件并格式化之
bool createDisk(string diskname, int size)
{
	//如果大小不合理
    if(size < 1 || size > 2 * 1024)
    {
        return false;
    }
    
    string filename = (diskname + ".disk");
    
    //如果创始空文件失败
    int result = CreateNullFile(filename, size * M);
    if(result == 0)
    {
        return false;
    }
    
    //自动格式化
    fstream file;
    file.open(filename, ios::binary | ios::out | ios::in);
    if(file.fail())
    {
    	//如果无法打开，则把刚创建的文件删除
        removeDisk(diskname);
        return false;
    }
    
    //初始化组描述符和超级块
    for(int i = 0; i < size; i++)
    {
        int base = i*M ;
        int groupPos = base + groupOffset;
        int superPos = base + superOffset;
        if(i == 0)          //初始化根结点和超级块
        {
            int indexPos = base + inodeOffset;           //第一个inode引用位置
            int inodePos = base + dataOffset;            //数据区的位置
            //写第一个inode
            file.seekp(inodePos);
            FCB fcb = __getEmptyFCB(1, indexPos);
            file.write((char*)&fcb, sizeof(fcb));
            file.seekp(indexPos);
            file.write((char*)&inodePos, 4);
            //写超级块
            file.seekp(superPos);
            SuperBlock superBlock;
            superBlock.mask = mask;
            superBlock.block_group_count = size;
            superBlock.root_addr = inodePos;
            file.write((char*)&superBlock, sizeof(superBlock));
        }
        //写组描述符
        file.seekp(groupPos);
        GroupDescription group;
        group.super_block = i == 0 ? superPos : 0;
        group.block_remain= i == 0 ? 1021 : 1022;
        group.index_remain= i == 0 ? 473 : 474;
        file.write((char*)&group, sizeof(group));
        //写块位图
        BlockBitmap bitmap;
        bitmap.bytes[0] = i == 0 ? 7 : 3;         //表示已经占用块
        file.seekp(base);
        file.write((char*)&bitmap, sizeof(bitmap));
    }
    
    //大小保持,为了保证创建的文件不缩水
    char end;
    int last = size * M - 1;
    file.seekg(last);
    file.read(&end,1);
    file.seekp(last);
    file.write(&end, 1);
    file.close();
    return true;
}

//删除一个文件
bool removeDisk(string diskname)
{
    string filename = diskname + ".disk";
    return unlink(filename.c_str());
}


//打开一个虚拟磁盘文件，直译超级块和根FCB
bool openDisk(string diskname, SuperBlock* & superBlock, FCB* & root)
{
    string filename = diskname + ".disk";
    ifstream file;
    file.open(filename, ios::binary | ios::in);
    if(file.fail())
    {
        return false;
    }
    int superPos = superOffset;
    FCB* fcb = new FCB;
    SuperBlock* su = new SuperBlock;
    file.seekg(superPos);
    file.read((char*)su, sizeof(SuperBlock));
    file.seekg(su->root_addr);
    file.read((char*)fcb, sizeof(FCB));
    file.close();
    
    superBlock = su;
    root = fcb;
    return true;
}


//创始一个新文件
bool createFile(string diskname, FCB dir, string newFilename, int type)
{
    string filename = diskname + ".disk";
    fstream file;
    file.open(filename, ios::binary | ios::in | ios::out);
    if(file.fail())
    {
        return 0;
    }
    
    //找一个空白的inode
    SuperBlock super;
    GroupDescription groupDes;
    file.seekg(superOffset);
    file.read((char*)&super, sizeof(super));
    int freeIndexAddr = -1;
    for(int i = 0; i < super.block_group_count; i++)
    {
        file.seekg(i*M + groupOffset);
        file.read((char*)&groupDes, sizeof(super));
        if(groupDes.index_remain > 0)
        {
            for(int j = 0; j < 474; j++)
            {
                int pos = i * M + inodeOffset + 4 * j;
                int addr;
                file.seekg(pos);
                file.read((char*)&addr, 4);
                if(addr == 0)
                {
                    freeIndexAddr = pos;
                    goto createProcess;
                }
            }
        }
    }
    createProcess :
    //如果找不到
    if(freeIndexAddr == -1)
    {
        return 0;
    }
    
    //如果找到了
    //进行文件创建操作
    //动作：更新组描述符、更新i结点区、更新文件控制块
    int blockAddr = __bindABlock(file, freeIndexAddr);   //获得空闲块地址并绑定
    //如果磁盘满了
    if(blockAddr == -1)
    {
        return 0;
    }
    
    //写一个FCB
    FCB fcb = __getEmptyFCB(type, freeIndexAddr);
    file.seekp(blockAddr);
    file.write((char*)&fcb, sizeof(fcb));
    
    //寻找空的表项
    dir = __reloadFCB(file, dir);
    DirItem dirItem;
    int writeStart = dir.bytes;
    for(int i = 0; i < dir.bytes / 256; i++)
    {
        int count = readFile(diskname, dir, (char*)(&dirItem), 256 * i, 256);
        if(count == 256 && dirItem.addr == 0)
        {
            writeStart = 256 * i;
            break;
        }
    }
    
    //更新目录
    strcpy(dirItem.filename, newFilename.c_str());
    dirItem.addr = blockAddr;
    writeFile(diskname, dir, (char*)&dirItem, writeStart, sizeof(dirItem));
    
    file.close();
    return true;
}


//删除文件
bool removeFile(string diskname, FCB dir, string newFilename)
{
    string filename = diskname + ".disk";
    fstream file;
    file.open(filename, ios::binary | ios::in | ios::out);
    if(file.fail())
    {
        return false;
    }
    
    //删除文件
    //动作0：找到pcb
    //动作1：解除内容块的使用
    //动作2：解除FCB块的使用
    //动作3：解除FCB块在inode区的引用
    //动作4：解除FCB在目录下的引用
    
    DirItem item;
    FCB* fcb = 0;
    int filePosInDir = 0;
    for(int i = 0; i < dir.bytes / 256; i++)
    {
        readFile(diskname, dir, (char*)&item, i*256, sizeof(item));
        if(item.addr != 0 && strcmp(newFilename.c_str(), item.filename) == 0)
        {
            fcb = __loadFCB(file, item.addr);
            filePosInDir = i*256;
            break;
        }  
    }
    
    //如果加载不出来
    if(fcb == 0)
    {
        return false;
    }
    
   	//计算占用的块数
    int virs = fcb->bytes / 1024;   //所有块的虚序号,从1开始
    if(fcb->bytes % 1024 != 0)
    {
        virs += 1;
    }
    
    int fileStart = __getAddrStart(file, *fcb);
    
    //第一阶段 
    for(int i = 0; i < 100 && virs > 0; i++, virs--)
    {
        int blockCiteStart = fileStart + i * 4;
        int blockStartAddr;
        file.seekg(blockCiteStart);
        file.read((char*)&blockStartAddr, 4);
        if(blockStartAddr != 0)
        {
            __releaseABlock(file, blockStartAddr);
            __setZero(file, blockCiteStart);           //删除块的引用
        }
    }
    
    //第二阶段
    fileStart += 100 * 4;
    for(int i = 0; i < 74 && virs > 0; i++)
    {
        int blockBlockCiteStart = fileStart + i * 4;
        int blockBlockAddr;
        file.seekg(blockBlockCiteStart);
        file.read((char*)&blockBlockAddr, 4);
        for(int j = 0; j < 256 && virs > 0; j++, virs--)
        {
            int blockCiteStart = blockBlockAddr + j * 4;
            int blockStartAddr;
            file.seekg(blockCiteStart);
            file.read((char*)&blockStartAddr, 4);
            __releaseABlock(file, blockStartAddr);
            __setZero(file, blockCiteStart);
            if(virs == 1 || j == 255)                   //如果是最后一个，删除此块
            {
                __releaseABlock(file, blockBlockAddr);
                __setZero(file, blockBlockCiteStart);
            }
        }
    }
    
    
    
    //第三阶段
    fileStart += 74 * 4;
    for(int i = 0; i < 64 && virs > 0; i++)
    {
    	int bbbStart = fileStart + i * 4;
    	int bbbAddr;
    	file.seekg(bbbStart);
    	file.read((char*)&bbbAddr, 4);
    	for(int j = 0; j < 256 && virs > 0; j++)
    	{
    		int bbStart = bbbAddr + j * 4;
    		int bbAddr;
    		file.seekg(bbStart);
    		file.read((char*)&bbAddr, 4);
    		for(int k = 0; k < 256 && virs > 0; k++, virs--)
    		{
    			int bStart = bbAddr + k * 4;
    			int bAddr;
    			file.seekg(bStart);
    			file.read((char*)&bAddr, 4);
    			__releaseABlock(file, bAddr);
    			__setZero(file, bStart);
    			if(virs == 1 || k == 255)
    			{
	    			__releaseABlock(file, bbAddr);
	    			__setZero(file, bbStart);
    			}
    		}
    		if(virs == 0 || j == 255)
    		{
    			__releaseABlock(file, bbbAddr);
	    		__setZero(file, bbbStart);
    		}
    	}
    }
    
    
    
    //解除fcb块的使用
    __releaseABlock(file, fileStart);
    //解除在inode区的引用
    __setZero(file, fcb->position);
    //解除在目录的引用
    item.addr = 0;
    writeFile(diskname, dir, (char*)&item, filePosInDir, sizeof(item));
    
    file.close();
    delete fcb;
    return true;
}

//读一个文件
int readFile(string diskname, FCB fcb, char* buffer, int start, int bytes)
{
    string filename = diskname + ".disk";
    fstream file;
    file.open(filename, ios::binary | ios::in | ios::out);
    if(file.fail())
    {
        return 0;
    }
    //重新加载pcb
    fcb = __reloadFCB(file, fcb);
    
    //位置是否合法
    if(start >= fcb.bytes)
    {
        return 0;
    }
    
    //数量是否合适
    int canRead = fcb.bytes - start;
    if(bytes > canRead)
    {
        bytes = canRead;
    }
    
    //循环读取
    int bufferStart = 0;
    int readPointer = start;
    int readOffset = start % 1024;
    int readCount = 1024 - readOffset;
    while(bytes > 0)
    {
        if(readCount > bytes)
        {
            readCount = bytes;
        }
        int block = __getActualAddr(file, fcb, readPointer / 1024);
        file.seekg(block + readOffset);
        file.read(buffer + bufferStart, readCount);
        
        readOffset = 0;
        bufferStart += readCount;
        readPointer += readCount;
        bytes -= readCount;
        readCount = 1024;
    }
    
    file.close();
    
    //返回实际读取的数量
    return bufferStart;
}



//写一个文件
int writeFile(string diskname, FCB fcb, char* buffer, int start, int bytes)
{
        string filename = diskname + ".disk";
        fstream file;
        file.open(filename, ios::binary | ios::in | ios::out);
        if(file.fail())
        {
            return 0;
        }
        //重新加载控制块
        fcb = __reloadFCB(file, fcb);
        
        //约束写入的地址
        if(start > fcb.bytes)
        {
            start = fcb.bytes;
        }
        
        //循环写入
        int offset = start % 1024;
        int count = 1024 - offset;               //写入的数量
        int offsetData = 0;
        while(bytes > 0)
        {
            if(count > bytes) count = bytes;
            int block = __getActualAddr(file, fcb, start / 1024);
            if(block == -1)                      //如果磁盘写满了
            {
                return block;
            }
            file.seekp(block + offset);
            file.write(buffer + offsetData, count);
            
            offsetData += count;
            start += count;
            bytes -= count;
            offset = 0;
            count = 1024;
        }
        
        //如果最后的位置大小原来的大小，则说明文件被扩充了
        if(start > fcb.bytes)   
        {
            fcb.bytes = start;
        	fcb.update_time = DateTime().toTimestamp();
        	
	        //更新控制块
	        __updateFCB(file, fcb);
        }
        
        file.close();
        
        //返回实际写的数量
        return offsetData;
}

//打开一个FCB，如果不存在则返回0
FCB* openFile(string diskname, FCB dir, string newFilename)
{
    string filename = diskname + ".disk";
    fstream file;
    file.open(filename, ios::binary | ios::in | ios::out);
    if(file.fail())
    {
        return 0;
    }
    
    //重新加载FCB
    dir = __reloadFCB(file, dir);
    DirItem item;
    FCB* fcb = new FCB;
    for(int i = 0; i < dir.bytes / 256; i++)
    {
        readFile(diskname, dir, (char*)&item, i * 256, sizeof(item));
        //找到了同名的FCB且是一个文件
        if(strcmp(newFilename.c_str(), item.filename) == 0)
        {
            file.seekg(item.addr);
            file.read((char*)fcb, sizeof(FCB));
            return fcb;
        }
    }
    
    file.close();
    return 0;
}

//重新加载
//因为重新加载可以确定fcb和disk一定有效,可以不用进行错误处理
FCB  reloadFile(string diskname, FCB fcb)
{
    fstream file(diskname + ".disk", ios::binary | ios::in | ios::out);
    return __reloadFCB(file, fcb);
}


//获得1-k块的使用情况
bool getFileSystemInfo(string diskname, int& total, int& remain)
{
	string filename = diskname + ".disk";
    fstream file;
    file.open(filename, ios::binary | ios::in | ios::out);
    if(file.fail())
    {
        return false;
    }
    
    //读取超级块程所有组描述符
    SuperBlock super;
    GroupDescription groupDes;
    file.seekg(superOffset);
    file.read((char*)&super, sizeof(super));
    int size = super.block_group_count;
    total = 1024 * size;
    remain = 0;
    for(int i = 0; i < size; i++)
    {
    	int groupStart = i * M + groupOffset;
    	file.seekg(groupStart);
    	file.read((char*)&groupDes, sizeof(groupDes));
    	remain += groupDes.block_remain;
    }
    
    return true;
}

/*********************************************工具函数**************************************/

//得到实际块地址
//vir是虚拟块地址，从0开始
//当访问某个块引用地址时，如果不存在（为0），则申请并绑定一个块
//如果绑定出错，则说明没有足够的空间，返回-1
int __getActualAddr(fstream& fs, FCB fcb, int vir)
{
    int start = __getAddrStart(fs,fcb);
    
    //直接块
    if(vir < 100)                           
    {
        int pos;
        start = start + vir * 4;
        fs.seekg(start);
        fs.read((char*)&pos, 4);
        if(pos == 0)  //如果为0,则表示此块不存在，立即绑定一个
        {
            pos = __bindABlock(fs, start);
        }
        return pos;
        
    //一级间接
    }else if(vir < 74 * 256 + 100)
    {
        start += 100 * 4;
        vir -= 100;
        int mul1 = vir / 256;
        int off1 = vir % 256;
        
        start += mul1 * 4;
        int backup1 = start;
        fs.seekg(start);
        fs.read((char*)&start, 4);
        if(start == 0)
        {
            start = __bindABlock(fs, backup1);
            if(start == -1) return start;
        }
        
        start += off1 * 4;
        int backup2 = start;
        fs.seekg(start);
        fs.read((char*)&start, 4);
        if(start == 0)
        {
            start = __bindABlock(fs, backup2);
        }
        
        return start;
        
    //二级间接
    }else
    {
        start += 174 * 4;
        vir -= (74 * 256 + 100);
        int blockTotal = 256 * 256;
        int mul1 = vir / blockTotal;
        int off1 = vir % blockTotal;
        
        start += mul1 * 4;
        int backup1 = start;
        fs.seekg(start);
        fs.read((char*)&start, 4);
        if(start == 0)
        {
            start = __bindABlock(fs, backup1);
            if(start == -1) return start;
        }
        
        int mul2 = off1 / 256;
        int off2 = off1 % 256;
        
        start += mul2 * 4;
        int backup2 = start;
        fs.seekg(start);
        fs.read((char*)&start, 4);
        if(start == 0)
        {
            start = __bindABlock(fs, backup2);
            if(start == -1) return start;
        }
        
        
        start += off2 * 4;
        int backup3 = start;
        fs.seekg(start);
        fs.read((char*)&start, 4);
        if(start == 0)
        {
            start = __bindABlock(fs, backup3);
        }
        return start;
    }
}




//绑定失败，则说明没有空闲块了，返回-1，否则返回地址
int __bindABlock(fstream& fs, int to)
{
	//获取
    int pos = __getABlock(fs);
    if(pos == -1)
    {
        return pos;
    }
    Block block;
    fs.seekp(pos);
    //清空
    fs.write((char*)&(block), sizeof(Block));
    fs.seekp(to);
    //绑定
    fs.write((char*)&pos, 4);
    //确认
    __comfirmABlock(fs, pos);
    return pos;
}




//得到文件直接块开始地址
int __getAddrStart(fstream& fs, FCB fcb)
{
    int cite;
    fs.seekg(fcb.position);
    fs.read((char*)&cite, 4);
    return cite + 72;
}


//得到一个空白块的地址
//错误返回 -1
int __getABlock(fstream& fs)
{
    SuperBlock super;
    fs.seekg(superOffset);
    fs.read((char*)&super, sizeof(super));
    int groupCount = super.block_group_count;
    
    //查找所有组描述符，看看是否有剩余的块
    for(int i = 0; i < groupCount; i++)
    {
        int bitPos = M * i;
        int groupPos = M * i + groupOffset;
        GroupDescription groupDes;
        fs.seekg(groupPos);
        fs.read((char*)&groupDes, sizeof(groupDes));
        
        //如果有剩余块茎，继续查找具体是哪个块
        if(groupDes.block_remain != 0)
        {
            BlockBitmap bitmap;
            fs.seekg(bitPos);
            fs.read((char*)&bitmap, sizeof(bitmap));
            int freePos = bitmap.get();
            
            //如是发生错误
            if(freePos == -1)
            {
                continue;
            }
            return bitPos + 1024 * freePos;
            break;
        }
    }
    
    return -1;
}



//确认一个块的使用
int __comfirmABlock(fstream& fs, int addr)
{
    int group = __getGroupId(addr);
    int bitPos = M * group;
    int groupPos = M * group + groupOffset;
    
    //读取位图
    BlockBitmap bitmap;
    fs.seekg(bitPos);
    fs.read((char*)&bitmap, sizeof(bitmap));
    
    //读取组描述符
    GroupDescription groupDes;
    fs.seekg(groupPos);
    fs.read((char*)&groupDes, sizeof(groupDes));
    
    //更新组描述符
    groupDes.block_remain -= 1;
    fs.seekp(groupPos);
    fs.write((char*)&groupDes, sizeof(groupDes));
    
    //更新位图
    addr -= bitPos;
    addr /= 1024;
    bitmap.set(addr, 1);
    fs.seekp(bitPos);
    fs.write((char*)&bitmap, sizeof(bitmap));
    return 0;
}



//解除一个块的使用
int __releaseABlock(fstream& fs, int addr)
{
    int group = __getGroupId(addr);
    int bitPos = M * group;
    int groupPos = M * group + groupOffset;
    
    //读取位图
    BlockBitmap bitmap;
    fs.seekg(bitPos);
    fs.read((char*)&bitmap, sizeof(bitmap));
    
    //读取组描述符
    GroupDescription groupDes;
    fs.seekg(groupPos);
    fs.read((char*)&groupDes, sizeof(groupDes));
    
    //更新组描述符
    groupDes.block_remain += 1;
    fs.seekp(groupPos);
    fs.write((char*)&groupDes, sizeof(groupDes));
    
    //更新位图
    addr -= bitPos;
    addr /= 1024;
    bitmap.set(addr, false);
    fs.seekp(bitPos);
    fs.write((char*)&bitmap, sizeof(bitmap));
    
    return 0;
}



//得到组号
//根据地址换算出属于哪个块组
int __getGroupId(int addr)
{
    int groupId = addr / M;
    return groupId;
}

//生成一个空的文件控制块
//主要是把扩展字段填上内容,防止杂物无章
FCB __getEmptyFCB(int type, int indexPos)
{
    FCB fcb;
    DateTime now;
    memset(&fcb, -1, 72);
    fcb.type = type;  
    fcb.bytes = 0;                             //文件大小(4byte) 
    fcb.create_time = now.toTimestamp();       //创建时间(4byte)
    fcb.update_time = now.toTimestamp();       //修改时间(4byte)
    fcb.visit_time = now.toTimestamp();        //访问时间(4byte)
    fcb.state = 0;                             //文件状态(4byte)
    fcb.count = 1;                             //引用计数(4byte)
    fcb.position = indexPos;                   //引用位置(4byte)
    return fcb;
}


//从某个地址加载一个文件控制块，并验证是否是真的文件控制块
//因为可能会传错地址
FCB* __loadFCB(fstream& fs, int addr)
{
    FCB* fcb = new FCB;
    fs.seekg(addr);
    fs.read((char*)fcb, sizeof(FCB));
    try
    {
       fs.seekg(fcb->position);
       int cite;
       fs.read((char*)&cite, 4);
       
       //如果验证一样，则证明是真的文件控制块
       if(cite == addr)
       {
           return fcb;
       } 
    }catch(exception e)
    {
        return 0;
    }
    
    return 0;
}


//重新加载文件控制块，因为文件控制块可能会因为更新而信息过时
FCB __reloadFCB(fstream& fs, FCB origin)
{
	int originType = origin.type;               //记下原来的类型
    int cite;
    fs.seekg(origin.position);
    fs.read((char*)&cite, 4);
    fs.seekg(cite);
    fs.read((char*)&origin, sizeof(origin));
    if(cite == 0 || origin.type != originType)  //如果重新读出错
    {
    	throw FCBInvalidError();
    }
    return origin;
}



//更新文件控制块
bool __updateFCB(fstream& fs, FCB origin)
{
    int cite;
    fs.seekg(origin.position);
    fs.read((char*)&cite, 4);
    fs.seekp(cite);
    fs.write((char*)&origin, sizeof(origin));
    return true;
}


//将某个整数置0
void __setZero(fstream& fs, int addr)
{
    int temp = 0;
    fs.seekp(addr);
    fs.write((char*)&temp, 4);
}


void test()
{
    //TODO：测试代码
}
